package org.cvcsc.weproject.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;

import org.cvcsc.weproject.controller.dto.RequestDtoUpdateCourseSchedule;
import org.cvcsc.weproject.controller.dto.ResponseDtoCourseSchedule;
import org.cvcsc.weproject.domain.CourseSchedule;
import org.cvcsc.weproject.repository.Finder;
import org.cvcsc.weproject.repository.ModelFinder;
import org.cvcsc.weproject.service.CourseScheduleService;
import org.cvcsc.weproject.service.CourseScheduleUpdateCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.Banner;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api/courses_schedule")
public class CourseScheduleController {

    @Autowired
    private CourseScheduleService courseScheduleService;
    @Autowired
    private Finder<CourseSchedule, Long> courseScheduleRepository;

    @Autowired
    private ModelFinder modelFinder;

    /**
     * 获取所有课程安排。
     *
     * @return 所有课程安排的列表
     */
    @GetMapping
    @Operation(summary = "获取所有课程安排", description = "返回系统中所有课程安排的列表")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取所有课程安排")
    })
    public List<ResponseDtoCourseSchedule> getAllCourseSchedules() {
        return courseScheduleRepository.findAll().stream()
                .map(ResponseDtoCourseSchedule::new)
                .collect(Collectors.toList());
    }

    /**
     * 根据ID获取单个课程安排。
     *
     * @param id 课程安排的ID
     * @return 课程安排对象
     */
    @GetMapping("/{id}")
    @Operation(summary = "根据ID获取单个课程安排", description = "通过ID查询单个课程安排")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取课程安排"),
            @ApiResponse(responseCode = "404", description = "未找到对应的课程安排")
    })
    public ResponseEntity<ResponseDtoCourseSchedule> getCourseScheduleById(@PathVariable Long id) {
        CourseSchedule courseSchedule = this.courseScheduleRepository.findById(id).orElseThrow(()-> new RuntimeException("课程安排不存在"));
        if (courseSchedule != null) {
            return ResponseEntity.ok(new ResponseDtoCourseSchedule(courseSchedule));
        } else {
            return ResponseEntity.notFound().build();
        }
    }

    /**
     * 创建新的课程安排。
     *
     * @param courseSchedules 新的课程安排对象
     * @return 创建的课程安排对象
     */
    @PostMapping
    @Operation(summary = "创建新的课程安排", description = "创建新的课程安排，clazz.id必须存在！")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "201", description = "成功创建课程安排"),
            @ApiResponse(responseCode = "400", description = "请求参数有误，无法创建课程安排")
    })
    public List<ResponseDtoCourseSchedule> createCourseSchedules(
            @RequestBody List<RequestDtoUpdateCourseSchedule> requestDtos) {
        List<CourseScheduleUpdateCommand> courseSchedules = requestDtos.stream()
                .map(dto -> new CourseScheduleUpdateCommand(dto.getClazzId(), dto.getCourseName(),
                        dto.getCourseScheduleTime()))
                .collect(Collectors.toList());
        List<Long> ids = courseScheduleService.createCourseSchedules(courseSchedules);
        return this.courseScheduleRepository.findAllById(ids).stream()
                .map(ResponseDtoCourseSchedule::new)
                .collect(Collectors.toList());
    }

    /**
     * 更新现有的课程安排。
     *
     * @param id             课程安排的ID
     * @param courseSchedule 更新后的课程安排对象
     * @return 更新后的课程安排对象
     */
    @PutMapping("/{id}")
    public ResponseDtoCourseSchedule updateCourseSchedule(
            @PathVariable Long id,
            @RequestBody RequestDtoUpdateCourseSchedule requestDtoUpdateCourseSchedule) {
        courseScheduleService.updateCourseSchedule(id,
                requestDtoUpdateCourseSchedule.toCommand());
        return this.courseScheduleRepository.findById(id)
                .map(ResponseDtoCourseSchedule::new)
                .orElseThrow(() -> new RuntimeException("课程安排不存在"));
    }

    /**
     * 删除指定ID的课程安排。
     *
     * @param id 课程安排的ID
     */
    @DeleteMapping("/{id}")
    public void deleteCourseSchedule(@PathVariable Long id) {
        courseScheduleService.deleteCourseSchedule(id);
    }

    /**
     * 删除所有课程安排。
     */
    @DeleteMapping
    @Operation(summary = "删除所有课程安排", description = "删除系统中所有的课程安排")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "204", description = "成功删除所有课程安排，无内容返回"),
            @ApiResponse(responseCode = "500", description = "服务器内部错误，删除课程安排失败")
    })
    public void deleteCourseScheduleAll() {
        courseScheduleService.deleteCourseScheduleAll();
    }

    /**
     * 查看某周某日指定班级的课程。
     *
     * @param week    周数
     * @param clazzId 班级ID
     * @return 某周的课程列表
     */
    @GetMapping("/week/{week}/clazz/{clazzId}")
    @Operation(summary = "查看某周指定班级的课程", description = "根据周数和班级ID获取课程列表")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取课程列表"),
            @ApiResponse(responseCode = "404", description = "未找到对应的课程安排")
    })
    public List<ResponseDtoCourseSchedule> getCoursesByClazzId(
            @Parameter(description = "周数") @PathVariable int week,
            @Parameter(description = "班级ID") @PathVariable Long clazzId) {
        return this.modelFinder.getCoursesByClazzId(week, clazzId).stream()
                .map(ResponseDtoCourseSchedule::new)
                .collect(Collectors.toList());
    }

    /**
     * 根据班级ID获取课程安排。
     *
     * @param clazzId 班级ID
     * @return 课程安排列表
     */
    @GetMapping("/clazz/{clazzId}")
    @Operation(summary = "根据班级ID获取课程安排", description = "根据班级ID获取所有相关的课程安排")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "200", description = "成功获取课程安排"),
            @ApiResponse(responseCode = "404", description = "未找到对应的课程安排")
    })
    public List<ResponseDtoCourseSchedule> getCoursesByClazzId(
            @Parameter(description = "班级ID") @PathVariable Long clazzId) {
        return this.modelFinder.getCoursesByClazzId(clazzId).stream()
                .map(ResponseDtoCourseSchedule::new)
                .collect(Collectors.toList());
    }
}
